package com.edushare.common.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.query.SelectQuery;

import com.edushare.common.mailer.ExistingUserInvite;
import com.edushare.common.mailer.Invite;
import com.edushare.common.orm.ORMInterface;
import com.edushare.common.vo.AcademicYearModel;
import com.edushare.common.vo.Batches;
import com.edushare.common.vo.CourseInstances;
import com.edushare.common.vo.Courses;
import com.edushare.common.vo.Enrolments;
import com.edushare.common.vo.Users;

public class EnrolmentsDAO extends CayenneBasedDAO {

	public EnrolmentsDAO(ORMInterface ormInterface) {
		super(ormInterface);		
	}
	
	public Enrolments getEnrolment(CourseInstances cI, Users u) {
		List<Enrolments> eL = u.getEnrolments();
		for(Enrolments e:eL){
			if(e.getCourseInstance() == cI){
				return e;
			}
		}
		return null;
	}

	public List<Users> getUsersByRole(CourseInstances cInst, int role) {
		List<Users> userList = new ArrayList<Users>();
		List<Enrolments> enrolList = cInst.getEnrolmentList();
		for (Enrolments e : enrolList) {
			if (e.getEnrolmentType() == role) {
				userList.add(e.getUser());
			}
		}
		return userList;
	}

	public boolean isUserPresent(CourseInstances cI, Users u) {
		if (getEnrolment(cI, u) != null)
			return true;
		return false;
	}
	
	public Enrolments addUser(CourseInstances cI, Users u, int roleType){
		return addUserWithStatus(cI, u, roleType, true);
	}

	public Enrolments addUserWithStatus(CourseInstances cI, Users u,
			int roleType, boolean invited) {
		if(isUserPresent(cI, u))
			return getEnrolment(cI, u);
		Enrolments e = new Enrolments();
		e.setCourseInstance(cI);
		e.setEnrolmentTimestamp(new Date());
		e.setEnrolmentType(roleType);
		e.setStatus(invited ? Enrolments.INVITED : Enrolments.ENROLLED);
		e.setUser(u);

		getDataContext().registerNewObject(e);
		getDataContext().commitChanges();
		return e;
	}
	
	public Enrolments enrolBatchStudents(CourseInstances courseInstance,
			Batches batchLink, int batchSemNum, Users user, int groupId) {
		Enrolments e = getEnrolment(courseInstance, user);
		if (e == null) {
			e = new Enrolments();
			getDataContext().registerNewObject(e);
			e.setCourseInstance(courseInstance);
			e.setUser(user);
		}
		e.setElectiveGroupId(groupId);
		e.setBatchLink(batchLink);
		e.setBatchSemNum(batchSemNum);
		e.setEnrolmentType(Enrolments.STUDENT);
		e.setStatus(Enrolments.ENROLLED);
		getDataContext().commitChanges();
		return e;
	}

	public Enrolments linkEnrolmentToBatch(Enrolments e, Batches batchLink,
			int batchSemNum) {
		e.setBatchLink(batchLink);
		e.setBatchSemNum(batchSemNum);
		getDataContext().commitChanges();
		return e;
	}

	public List<Enrolments> getNormalEnrolments(Users u,
			AcademicYearModel semester, int calendarYear, Batches batch) {
		List<Enrolments> normalEnrolList = new ArrayList<Enrolments>();
		List<Enrolments> enrolList = u.getEnrolments();
		for (Enrolments e : enrolList) {
			CourseInstances inst = e.getCourseInstance();
			if (e.getBatchLink() == batch
					&& inst.getInstanceYear() == calendarYear
					&& inst.getSemester() == semester) {
				normalEnrolList.add(e);
			}
		}
		return normalEnrolList;
	}

	public List<Enrolments> getUnlinkedEnrolments(Users u,
			AcademicYearModel semester, int calendarYear) {
		List<Enrolments> enrolList = u.getEnrolments();
		List<Enrolments> unlinkedEnrols = new ArrayList<Enrolments>();
		for (Enrolments e : enrolList) {
			CourseInstances inst = e.getCourseInstance();
			if (inst.getInstanceYear() == calendarYear
					&& inst.getSemester() == semester
					&& e.getBatchLink() == null)
				unlinkedEnrols.add(e);
		}
		return unlinkedEnrols;
	}

	public Enrolments unlinkEnrolmentFromBatch(Enrolments e) {
		e.setBatchLink(null);
		getDataContext().commitChanges();
		return e;
	}

	public Enrolments changeRole(CourseInstances cI, Users u, int roleType){
		if(!isUserPresent(cI, u))
			return null;
		Enrolments e = getEnrolment(cI, u);
				e.setEnrolmentType(roleType);
		if (roleType == Enrolments.TEACHER
				|| roleType == Enrolments.TEACHING_ASSISTANT)
					e.setStatus(Enrolments.ENROLLED);
				getDataContext().commitChanges();
				return e;
			}

	@SuppressWarnings("unchecked")
	public List<Enrolments> getEnrolmentsByRole(CourseInstances courseInstance,
			int enrolledAs) {
		Expression exp = Expression.fromString("courseInstance = $ci and "
				+ "enrolmentType = $role");
		HashMap<String, Object> params = new HashMap<String,Object>();
		params.put("ci", courseInstance);
		params.put("role", enrolledAs);
		
		SelectQuery query = new SelectQuery(Enrolments.class, exp
				.expWithParameters(params));
		return getDataContext().performQuery(query);
	}
	
	public Enrolments changeStatus(CourseInstances cI, Users u, int status){
		if(!isUserPresent(cI, u)){
			return null;
		}
		Enrolments e = getEnrolment(cI, u);
				e.setStatus(status);				
				getDataContext().commitChanges();
				return e;
			}
	
	public String addUserFB(CourseInstances cI, Users u, int roleType,
			Users from) {
		if(isUserPresent(cI, u))
			return "User " + u.getCompleteUserName() + " already present in "
					+ cI.getCourse().getCourseName();
		else{
			if(addUser(cI, u, roleType)!= null){
				if (u.getStatus() == Users.ACTIVE) {
					new OutgoingEmailsDAO(ormInterface)
							.sendMail(new ExistingUserInvite(u, from, cI)
									.send());
				} else {
					new OutgoingEmailsDAO(ormInterface).sendMail(new Invite(u,
							cI, roleType, from).send());
				}
				return "Invited " + u.getCompleteUserName() + " to "
						+ cI.getCourse().getCourseName();
			}else
				return "Unable to add " + u.getCompleteUserName() + " to "
						+ cI.getCourse().getCourseName();
		}
	}
	
	public void removeUser(CourseInstances cI, Users u){
		Enrolments e = getEnrolment(cI, u);
		if (e != null) {
			getDataContext().deleteObject(e);
			getDataContext().commitChanges();
			}
		}
	
	public List<Courses> getUserCompletedCourses(Users user){
		List<Enrolments> enrol = user.getEnrolments();
		List<Courses> courseList = new ArrayList<Courses>();
		for(Enrolments e:enrol){
			if (e.getEnrolmentType() == Enrolments.STUDENT
					|| e.getEnrolmentType() == Enrolments.OBSERVER) {
				if(e.getStatus() == Enrolments.COMPLETED){
					courseList.add(e.getCourseInstance().getCourse());
				}
			}
		}
		return courseList;
	}
	
	public List<Enrolments> getOutstandingInvites(Users user){
		List<Enrolments> enrol = user.getEnrolments();
		List<Enrolments> rtList = new ArrayList<Enrolments>();
		for(Enrolments e:enrol){
			if(e.getStatus()==Enrolments.INVITED){
				rtList.add(e);
			}
		}
		return rtList;
	}
	
	public void enrolStudents(CourseInstances courseInst,
			List<Users> studentList) {
		for(Users student:studentList){
			enrolStudent(courseInst, student);
		}
	}

	public void enrolStudent(CourseInstances courseInst, Users student) {
			Enrolments e = addUser(courseInst, student, Enrolments.STUDENT);
			if(e != null)
				e.setStatus(Enrolments.ENROLLED);
		getDataContext().commitChanges();
	}
	
	public void enrolTeachers(CourseInstances courseInst,
			List<Users> teacherList) {
		for(Users teacher:teacherList){
			Enrolments e = addUser(courseInst, teacher, Enrolments.TEACHER);
			if(e != null)
				e.setStatus(Enrolments.ENROLLED);
		}
		getDataContext().commitChanges();
	}

	public void configureNewEnrolemnt(Enrolments enrolment) {
		new UserAssignmentLinkDAO(ormInterface)
				.assignOpenToNewEnrolment(enrolment);
	}
	
}
